using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Security;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;

using CoolStuffs.Sharepoint.Webparts.RecentItems.Common;
using CoolStuffs.Sharepoint.Webparts.RecentItems.Support;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

namespace CoolStuffs.Sharepoint.Webparts.RecentItems
{
    /// <summary>
    /// The Base webpart for content agregation
    /// Other webparts must derive this webpart
    /// </summary>
    public abstract class BaseContentAggregator : System.Web.UI.WebControls.WebParts.WebPart
    {
        #region Nested Enums/Structures/Classes

        #region Public
        /// <summary>
        /// Scope of the Search:
        /// None : Current Site Only
        /// Site : Entire SiteCollection
        /// Web : Current Site and SubSites
        /// </summary>
        public enum SearchScope
        {
            None,
            Site,
            Web
        }

        /// <summary>
        /// Field to Group the Items
        /// in the Grid By
        /// </summary>
        public enum GroupByScope
        {
            None,
            Site,
            ModifiedOn,
            CreatedOn,
            ModifiedBy,
            List
        }

        /// <summary>
        /// Base Content Type
        /// of the Items to display
        /// </summary>
        public enum DocumentBaseTypeScope
        {
            GenericList = 0,
            DocumentLibrary = 1,
            DiscussionForum = 3,
            Survey = 4,
            IssueList = 5
        }
        #endregion

        #region Protected
        #endregion

        #region Private
        #endregion

        #region Internal
        #endregion

        #endregion

        #region Member Variables

        #region Public
        #endregion

        #region Protected

        /// <summary>
        /// Document type scope
        /// </summary>
        protected DocumentBaseTypeScope DocumentTypeBase;
        #endregion

        #region Internal
        #endregion

        #region Private
        private Microsoft.SharePoint.WebControls.SPGridView _gdAggregatorGrid;
        private Microsoft.SharePoint.SPWeb _web;
        private System.Web.UI.WebControls.Label _lblErrorOutput;
        private System.Data.DataView _recentItemsDataView;
        private System.Int32 _limit = default(System.Int32);
        private System.Int32 _pageSize = default(System.Int32);
        private System.Boolean _viewCreatedColumn;
        private System.Data.DataTable _recentItemsDataTable;
        private System.Boolean _viewModifiedColumn;
        private System.Boolean _viewListNameColumn;
        private System.Boolean _viewSiteNameColumn;
        private System.Boolean _viewModifiedByColumn;
        private System.Collections.Generic.Dictionary<DocumentBaseTypeScope, StringCollection> _fieldsInDocumentType;
        private System.Collections.Specialized.StringCollection _commonColumns;
        private GroupByScope _groupBy;
        private SearchScope _searchScope;
        private System.String _sortExpression = String.Empty;
        private System.String _sortDirection = String.Empty;
        private System.String _hash = "#";
        private System.String _queryStrings = String.Empty;
        private const System.String _baseTableName = "RecentItemsTable";
        private const System.String _createdOnField = "Created";
        private const System.String _modifiedOnField = "Modified";
        private const System.String _modifiedByField = "Editor";
        private const System.String _webId = "WebId";
        private const System.String _listId = "ListId";
        private const System.String _itemId = "ID";
        private const System.String _userDispFormUrlField = "UserDispFormUrl";
        private const System.String _siteName = "ProjectProperty.Title";
        private const System.String _iconUrl = "Image";
        private const System.String _itemDispFormUrl = "ItemDisplayFormUrl";
        private const System.String _listName = "ListProperty.Title";
        private const System.String _viewFieldsTemplate = "<FieldRef Name='{0}'/>";
        private const System.String _imagesPath = @"\Microsoft Shared\web server extensions\12\TEMPLATE\IMAGES\";
        private const System.String _genericIconUrl = "/_layouts/images/icgen.gif";
        private const System.String _folderIconUrl = "/_layouts/images/folder.gif";
        private const System.String _imagesPathRoot = "/_layouts/images/";
        private const System.String _orderByQueryTemplate = "<OrderBy><FieldRef Name='{0}' Ascending=\"False\"/></OrderBy>";
        private const System.String _siteAndListPropertiesTemplate = "<ProjectProperty Name='Title' />" +
                                                                        "<ListProperty Name='Title' />";
        private const System.String _listBaseTypTemplate = "<Lists BaseType='{0}' Hidden=\"FALSE\" />";
        private const System.String _iconNameTemplate = "ic{0}.gif";
        private const System.String _searchEntireSiteCollection = "<Webs Scope='SiteCollection'>";
        private const System.String _searchOnlyCurrentSiteAndSubsite = "<Webs Scope='Recursive'>";
        private const System.String _gridViewId = "8A9842F1-5A3D-4863-AEA8-8959932F4CE4_aggregatorGrid";
        private const System.String _emptyGridTemplateText = "There are Currently No Items to show in this View." +
                                                                "Click \"Modify Webpart\" and check whether required" +
                                                                "properties are set in \"Presentation\" Section";
        private const System.String _createdOnDisplayText = "Created On";
        private const System.String _modifiedOnDisplayText = "Modified On";
        private const System.String _modifiedByDisplayText = "Modified By";
        private const System.String _listNameDisplayText = "List Name";
        private const System.String _siteNameDisplayText = "Site Name";
        private const System.String _typeDisplayText = "Type";
        private const System.String _sortTemplate = "[{0}] {1}";
        private const System.String _rowFilterTemplate = "[{0}] = '{1}'";
        private const System.String _ascendingDirection = "asc";
        private const System.String _descendingDirection = "desc";
        private const System.String _separator = ";#";
        private const System.String _dot = ".";
        private const char _amp = '&';
        private const System.String _id = "?ID=";
        private const System.String _message = "There is no implementation in Base Class." +
                " Override this function to provide your custom Implementation";
        private const System.String _staticPageRelativeUrl = "/_layouts/RecentDocuments.aspx";
        private const System.String _titleUrlTemplate = "{0}" + _staticPageRelativeUrl+ "?{1}";
        private const System.String _queryStringTemplate = "&{0}={1}";
        #endregion

        #endregion

        #region Constructors/Destructors

        #region Public
        /// <summary>
        /// Default constructor, Initializes the
        /// required members and adds comon columns in 
        /// column collection
        /// </summary>
        public BaseContentAggregator()
            : base()
        {
            _gdAggregatorGrid = new SPGridView();
            _lblErrorOutput = new Label();
            _commonColumns = new StringCollection();
            _commonColumns.Add(this.CreatedOnField);
            _commonColumns.Add(this.ModifiedOnField);
            _commonColumns.Add(this.ModifiedByField);
            _fieldsInDocumentType = new Dictionary<DocumentBaseTypeScope, StringCollection>();
            _fieldsInDocumentType.Add(DocumentBaseTypeScope.GenericList, new StringCollection());
            _fieldsInDocumentType.Add(DocumentBaseTypeScope.DocumentLibrary, new StringCollection());
            _fieldsInDocumentType.Add(DocumentBaseTypeScope.Survey, new StringCollection());
            _fieldsInDocumentType.Add(DocumentBaseTypeScope.IssueList, new StringCollection());
            _fieldsInDocumentType.Add(DocumentBaseTypeScope.DiscussionForum, new StringCollection());
            if (SPContext.Current != null)
            {
                _web = SPContext.Current.Web;
            }
        }

        #endregion

        #region Protected
        #endregion

        #region Private
        #endregion

        #region Internal
        #endregion

        #endregion

        #region Properties

        #region Public

        /// <summary>
        /// Get/Set the base List content type of the 
        /// Items to display
        /// </summary>
        public DocumentBaseTypeScope DocumentType
        {
            get
            {
                return this.DocumentTypeBase;
            }
            set
            {
                this.DocumentTypeBase = value;
            }
        }

        /// <summary>
        /// The datacolumn to sort on, in Datatable
        /// </summary>
        public System.String SortExpression
        {
            get
            {
                return this._sortExpression;
            }
            set
            {
                this._sortExpression = value;
            }
        }

        /// <summary>
        /// direction of sort, whether asc/desc
        /// </summary>
        public System.String SortDirection
        {
            get
            {
                return this._sortDirection;
            }
            set
            {
                this._sortDirection = value;
            }
        }

        /// <summary>
        /// Get/Set Whether or Not to
        /// show the 'Modified On' Column
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [Category("Presentation")]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("View 'Modified On' column")]
        [XmlElement(ElementName = "ModifiedColumn")]
        public Boolean ViewModifiedOnColumn
        {
            get
            {
                return this._viewModifiedColumn;
            }
            set
            {
                this._viewModifiedColumn = value;
            }
        }

        /// <summary>
        /// Get/Set Whether or Not to
        /// show the 'Created On' Column
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [Category("Presentation")]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("View 'Created On' column")]
        [XmlElement(ElementName = "CreatedColumn")]
        public Boolean ViewCreatedOnColumn
        {
            get
            {
                return this._viewCreatedColumn;
            }
            set
            {
                this._viewCreatedColumn = value;
            }
        }

        /// <summary>
        /// Get/Set Whether or Not to
        /// show the 'Modified By' Column
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [Category("Presentation")]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("View 'Modified By' Column")]
        [XmlElement(ElementName = "ModifiedBy")]
        public Boolean ViewModifiedByColumn
        {
            get
            {
                return this._viewModifiedByColumn;
            }
            set
            {
                this._viewModifiedByColumn = value;
            }
        }

        /// <summary>
        /// Get/Set Whether or Not to
        /// show the 'List Name' Column
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("View 'List Name' column")]
        [Category("Presentation")]
        [XmlElement(ElementName = "ListColumn")]
        public Boolean ViewListNameColumn
        {
            get
            {
                return this._viewListNameColumn;
            }
            set
            {
                this._viewListNameColumn = value;
            }
        }

        /// <summary>
        /// Get/Set Whether or Not to
        /// show the 'Site Name' Column
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("View 'Site Name' column")]
        [Category("Presentation")]
        [XmlElement(ElementName = "SiteColumn")]
        public Boolean ViewSiteNameColumn
        {
            get
            {
                return this._viewSiteNameColumn;
            }
            set
            {
                this._viewSiteNameColumn = value;
            }
        }

        /// <summary>
        /// Get/Set How many Items
        /// can be viewed in one listing
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("Total Items in List")]
        [Category("Presentation")]
        [XmlElement(ElementName = "Limit")]
        public Int32 ItemLimit
        {
            get
            {
                return Math.Abs(this._limit);
            }
            set
            {
                this._limit = Math.Abs(value);
            }
        }

        /// <summary>
        /// Get/Set How many items
        /// to show on one page
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("Total Items on a Page")]
        [Category("Presentation")]
        [XmlElement(ElementName = "PageSize")]
        public Int32 PageSize
        {
            get
            {
                return Math.Abs(this._pageSize);
            }
            set
            {
                this._pageSize = Math.Abs(value);
            }
        }

        /// <summary>
        /// Get/Set Which field to Group 
        /// the items in the list By
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("Group By property")]
        [Category("Presentation")]
        [XmlElement(ElementName = "GroupBy")]
        public GroupByScope GroupBy
        {
            get
            {
                return this._groupBy;
            }
            set
            {
                this._groupBy = value;
            }
        }

        /// <summary>
        /// Get/Set What is the 
        /// search scope of the query
        /// <remarks>
        /// This Property is Personalizable property
        /// and is at the End users disposle
        /// </remarks>
        /// </summary>
        [WebBrowsable(true)]
        [Personalizable(true)]
        [WebPartStorage(Storage.Personal)]
        [FriendlyNameAttribute("Scope of the query")]
        [Category("Presentation")]
        [XmlElement(ElementName = "Scope")]
        public SearchScope SearchOptions
        {
            get
            {
                return this._searchScope;
            }
            set
            {
                this._searchScope = value;
            }
        }

        /// <summary>
        /// Hash to check in the URL
        /// </summary>
        public System.String Hash
        {
            get
            {
                return this._hash;
            }
        }

        #endregion

        #region Protected

        /// <summary>
        /// Get Grid used to display the Items
        /// </summary>
        protected SPGridView uxAggregatorGridView
        {
            get
            {
                return this._gdAggregatorGrid;
            }
        }

        /// <summary>
        /// Get Label used to show error/other messages
        /// </summary>
        protected Label ErrorLabel
        {
            get
            {
                return this._lblErrorOutput;
            }
        }

        /// <summary>
        /// Get the Name of 'Created On' Field
        /// in the View
        /// </summary>
        protected System.String CreatedOnField
        {
            get
            {
                return _createdOnField;
            }
        }

        /// <summary>
        /// Get the Name of 'Modified On' Field
        /// </summary>
        protected System.String ModifiedOnField
        {
            get
            {
                return _modifiedOnField;
            }
        }

        /// <summary>
        /// Get the Name of 'Modified By' Field
        /// </summary>
        protected System.String ModifiedByField
        {
            get
            {
                return _modifiedByField;
            }
        }

        /// <summary>
        /// Get the Name of 'Site Name' Field
        /// </summary>
        protected System.String SiteNameField
        {
            get
            {
                return _siteName;
            }
        }

        /// <summary>
        /// Get the Name of 'List Name' Field
        /// </summary>
        protected System.String ListNameField
        {
            get
            {
                return _listName;
            }
        }

        /// <summary>
        /// Get the Name of 'Modified On' Field
        /// </summary>
        protected System.String IconUrlField
        {
            get
            {
                return _iconUrl;
            }
        }

        /// <summary>
        /// Get the Name of Item's 
        /// Display Form URL Field. This column in
        /// in Dataview holds Item's Display URL
        /// e.g.: /Library/Forms/DispForm.aspx?ID=4
        /// </summary>
        protected System.String ItemDisplayFormUrlField
        {
            get
            {
                return _itemDispFormUrl;
            }
        }

        /// <summary>
        /// Get the User Display Form Url field Name.
        /// This Field in DataView holds the 'Modified By' User's
        /// Display Form URL
        /// e.g.: /_layouts/UserDisp.aspx?ID=12
        /// </summary>
        protected System.String UserDisplayFormUrlField
        {
            get
            {
                return _userDispFormUrlField;
            }
        }

        /// <summary>
        /// Get Name of the Base table
        /// </summary>
        protected System.String BaseTableName
        {
            get
            {
                return _baseTableName;
            }
        }

        /// <summary>
        /// Get/Set the final DataView
        /// to bind to the Grid
        /// </summary>
        protected System.Data.DataView RecentItemsDataView
        {
            get
            {
                return this._recentItemsDataView;
            }
            set
            {
                this._recentItemsDataView = value;
            }
        }

        /// <summary>
        /// Get StringCollection of Field Names in Specified
        /// Document Type
        /// </summary>
        protected System.Collections.Generic.Dictionary<DocumentBaseTypeScope,
            StringCollection> FieldsInDocumentType
        {
            get
            {
                return this._fieldsInDocumentType;
            }
        }

        #endregion

        #region Private
        #endregion

        #region Internal
        #endregion

        #endregion

        #region Methods

        #region Public
        #endregion

        #region Protected

        /// <summary>
        /// OnInt event of the page
        /// </summary>
        /// <param name="e"></param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            this.Page.RegisterRequiresControlState(this);
        }

        /// <summary>
        /// Load the control state in localvariables
        /// </summary>
        /// <param name="savedState">object</param>
        protected override void LoadControlState(object savedState)
        {
            base.LoadControlState(savedState);
            if (savedState != null)
            {
                string[] _stateBag = (savedState as string).Split(new string[1] { _separator },
                                        StringSplitOptions.RemoveEmptyEntries);
                if (_stateBag.Length > 0)
                {
                    this.SortExpression = _stateBag[0];
                    this.SortDirection = _stateBag[1];
                }
            }
        }

        /// <summary>
        /// save the controls state back to the page
        /// </summary>
        /// <returns>saved object</returns>
        protected override object SaveControlState()
        {
            StringBuilder _stringBuilder = new StringBuilder();
            _stringBuilder.Append(this.SortExpression);
            _stringBuilder.Append(_separator);
            _stringBuilder.Append(this.SortDirection);
            return _stringBuilder.ToString();
        }

        /// <summary>
        /// This Method initializes the final DataView,
        /// gets the Items with desired columns in the view
        /// through SPSiteDataQuery
        /// Apart from those supplied in the FieldInDocumentType Collection
        /// it also gets User Display Form URL field and Item Display Form
        /// URL Field
        /// </summary>
        /// <param name="FieldName"></param>
        protected void GetRecentItemsDataView(string fieldName)
        {
            StringCollection _allColumnsCollection = this._commonColumns;
            this._recentItemsDataTable = new DataTable();
            foreach (String documentTypeSpecificColumn in this.FieldsInDocumentType[this.DocumentType])
            {
                _allColumnsCollection.Add(documentTypeSpecificColumn);
            }
            Microsoft.SharePoint.SPSiteDataQuery _siteDataQuery = this.GetSPSiteDataQuery(_allColumnsCollection);
            _recentItemsDataTable = _web.GetSiteData(_siteDataQuery);
            _recentItemsDataTable.TableName = this.BaseTableName;
            this.AddColumnToDataTable(this.UserDisplayFormUrlField);
            this.AddColumnToDataTable(this.IconUrlField);
            this.AddColumnToDataTable(this.ItemDisplayFormUrlField);
            foreach (DataRow _row in _recentItemsDataTable.Rows)
            {
                string _fieldName = _row[fieldName].ToString();
                string _extension = string.Empty;
                string _image = string.Empty;
                string _url = string.Empty;
                string _iconFileName = string.Empty;
                string _iconFilePhysicalPath = string.Empty;
                string _commonProgramFilesPath =
                    Environment.GetFolderPath(System.Environment.SpecialFolder.CommonProgramFiles);
                ///MOSS always installs its stuffs in this directory of %commonprogramfiles%
                /// what is more important above is that you dont hard code :
                /// c:\program files\common files
                _commonProgramFilesPath += _imagesPath;
                if (_fieldName.LastIndexOf(_dot) != -1)
                {
                    /// Item is a file with some extension
                    _extension = _fieldName.Substring(_fieldName.LastIndexOf(_dot) + 1);

                    _iconFileName = string.Format(_iconNameTemplate, _extension);
                    _image = _imagesPathRoot + _iconFileName;
                    try
                    {
                        _iconFilePhysicalPath = _commonProgramFilesPath + _iconFileName;
                        using (System.IO.FileStream _iconFileStream =
                            System.IO.File.Open(_iconFilePhysicalPath,
                            System.IO.FileMode.Open,
                            System.IO.FileAccess.Read))
                        {
                            _iconFileStream.Close();
                        }
                    }
                    catch (System.IO.FileNotFoundException)
                    {
                        /// the icon for this type of file extension 
                        /// is not found in the icon repository,
                        /// so setting the generic 'Type' icon
                        _image = _genericIconUrl;
                    }
                }
                else if (this.BaseTypeNotDocument())
                {
                    /// Its a List Type Item
                    _image = _genericIconUrl;
                }
                else
                {
                    /// Its a Folder
                    _image = _folderIconUrl;
                }
                _row[this.IconUrlField] = _image;
                string _modifiedBy = _row[this.ModifiedByField].ToString();
                if (!string.IsNullOrEmpty(_modifiedBy))
                {
                    string _modifiedById = _modifiedBy.
                                            Substring(_modifiedBy.IndexOf(this.Hash) - 2, 1);
                    _row[this.ModifiedByField] = _modifiedBy.Substring(_modifiedBy.IndexOf(this.Hash) + 1);
                    _row[this.UserDisplayFormUrlField] =
                                    _web.SiteUserInfoList.
                                    Forms[PAGETYPE.PAGE_DISPLAYFORM].ServerRelativeUrl +
                                    _id + _modifiedById;
                    StringBuilder _urlBuilder = new StringBuilder();
                    _urlBuilder.Append(Page.Request.Url.GetLeftPart(UriPartial.Authority));
                    _urlBuilder.Append(SPContext.Current.Site.OpenWeb(new Guid(_row[_webId].ToString())).
                                                Lists[new Guid(_row[_listId].ToString())].
                                                Forms[PAGETYPE.PAGE_DISPLAYFORM].ServerRelativeUrl);
                    _urlBuilder.Append(_id);
                    _urlBuilder.Append(_row[_itemId].ToString());
                    _row[this.ItemDisplayFormUrlField] = _urlBuilder.ToString();
                    _row.AcceptChanges();
                }
            }
            _recentItemsDataView = new DataView(_recentItemsDataTable);
        }

        /// <summary>
        /// Check Whether the Current Content Type is
        /// Document or Not. The Check is made on properties
        /// wrapping the protected field _enDocumentType
        /// </summary>
        /// <returns></returns>
        protected bool BaseTypeNotDocument()
        {
            switch (this.DocumentTypeBase)
            {
                case DocumentBaseTypeScope.GenericList:
                    return true;
                case DocumentBaseTypeScope.IssueList:
                    return true;
                case DocumentBaseTypeScope.Survey:
                    return true;
                case DocumentBaseTypeScope.DocumentLibrary:
                    return false;
                default: return true;
            }
        }

        /// <summary>
        /// Gets the Initialized SPSiteDataQuery
        /// with ViewFields set with those passed in parameter
        /// </summary>
        /// <param name="viewFieldsCollction">Collection of Fields in Final DataView to bind</param>
        /// <returns></returns>
        protected SPSiteDataQuery GetSPSiteDataQuery(StringCollection viewFieldsCollection)
        {
            Microsoft.SharePoint.SPSiteDataQuery _siteDataQuery = new SPSiteDataQuery();
            _siteDataQuery.Query = string.Format(_orderByQueryTemplate, this.CreatedOnField);
            _siteDataQuery.RowLimit = Convert.ToUInt32(this.ItemLimit);
            StringBuilder _viewFieldsBuilder = new StringBuilder();
            foreach (string viewfield in viewFieldsCollection)
            {
                _viewFieldsBuilder.Append(string.Format(_viewFieldsTemplate, viewfield));
            }
            _siteDataQuery.ViewFields = _viewFieldsBuilder.ToString() + _siteAndListPropertiesTemplate;
            _siteDataQuery.Lists = string.Format(_listBaseTypTemplate,
                                                    Convert.ToInt32(this.DocumentTypeBase));
            switch (this.SearchOptions)
            {
                case SearchScope.Site: _siteDataQuery.Webs = _searchEntireSiteCollection;
                    break;
                case SearchScope.Web: _siteDataQuery.Webs = _searchOnlyCurrentSiteAndSubsite;
                    break;
                case SearchScope.None: _siteDataQuery.Webs = string.Empty;
                    break;
                default: break;
            }
            return _siteDataQuery;
        }

        /// <summary>
        /// CreateChildControl Event of System.Web.UI.WebControls.Webparts.Webpart
        /// </summary>
        protected override void CreateChildControls()
        {
            this.EnsureChildControls();
            this.generateGrid();
            this._gdAggregatorGrid.AutoGenerateColumns = false;
            this.Controls.Add(this._lblErrorOutput);
            this.Controls.Add(this._gdAggregatorGrid);
            this._gdAggregatorGrid.PagerTemplate = null;
            base.CreateChildControls();
        }

        /// <summary>
        /// Insert the Name Field in Grid supplying the required
        /// column names of columns that get the display name of the Item
        /// as well as navigation Url in hyperlink field
        /// </summary>
        /// <param name="DataNavigateUrlFields">fields used to form items navigation Url</param>
        /// <param name="DataTextField">Column Name in Final DataView to Bind Grid</param>
        /// <param name="HeaderText">Header Text on Grid's Name COlumn</param>
        protected void InsertItemNameFieldInGrid(string[] dataNavigateUrlFields,
            string dataTextField,
            string headerText)
        {
            HyperLinkField _fileNameField = new HyperLinkField();
            _fileNameField.DataNavigateUrlFields = dataNavigateUrlFields;
            _fileNameField.DataTextField = dataTextField;
            _fileNameField.HeaderText = headerText;
            _fileNameField.SortExpression = dataTextField;
            this.uxAggregatorGridView.Columns.Insert(1, _fileNameField);
        }

        /// <summary>
        /// Groups the DataView as per the Current GroupBy Field
        /// Then Sorts the Items in each group
        /// </summary>
        /// <param name="groupByScope">Current GroupBy Scope</param>
        /// <param name="sortField">field to sort items on</param>
        /// <param name="sortDirection">Direction to sort</param>
        /// <returns>Grouped and Sorted DataView</returns>
        protected DataView GetSortedItemsViewInGroups(string sortField, string sortDirection)
        {
            DataTable _tempTable = this._recentItemsDataView.ToTable();
            DataTable _finalTable = _tempTable.Clone();
            _finalTable.Clear();
            string _groupByField = this.getGroupByProperty(this.GroupBy);
            if (!string.IsNullOrEmpty(_groupByField) && (_tempTable != null) && (_tempTable.Rows.Count > 0))
            {
                DataSetHelper _dataSetHelper = new DataSetHelper();
                DataTable _distinctGroupByFieldsTable = _dataSetHelper.SelectDistinct(_tempTable.TableName,
                    _tempTable, _groupByField);
                DataView _tempView;
                foreach (DataRow _distinctGroupByFieldRow in _distinctGroupByFieldsTable.Rows)
                {
                    _tempView = new DataView(_tempTable);
                    _tempView.RowFilter = string.Format(_rowFilterTemplate, _groupByField,
                        _distinctGroupByFieldRow[0].ToString());
                    if (!string.IsNullOrEmpty(sortField) || !string.IsNullOrEmpty(sortDirection))
                    {
                        _tempView.Sort = string.Format(_sortTemplate, sortField, sortDirection);
                    }
                    _finalTable.Merge(_tempView.ToTable());
                }
                return new DataView(_finalTable);
            }
            else
            {
                return this._recentItemsDataView;
            }
        }

        /// <summary>
        /// Bind the GridView with the final sorted view
        /// </summary>
        protected void BindGrid()
        {
            this.uxAggregatorGridView.DataSource = this.GetSortedItemsViewInGroups(this.SortExpression,
                this.SortDirection);
        }
        /// <summary>
        /// To construct Title Url on Pre-Render Event
        /// </summary>
        /// <param name="e">EventArgs</param>
        protected override void OnPreRender(EventArgs e)
        {
            //this.generateGrid();
            this.makeQueryString();
            this.TitleUrl = string.Format(_titleUrlTemplate, _web.Url, this._queryStrings);
        }

        /// <summary>
        /// Render Event of System.Web.UI.WebControls.WebParts.WebPart
        /// </summary>
        /// <param name="writer">HtmlTextWriter object used to render</param>
        protected override void Render(HtmlTextWriter writer)
        {
            try
            {
                this.ErrorLabel.RenderControl(writer);
                this.uxAggregatorGridView.DataBind();
                this.uxAggregatorGridView.RenderControl(writer);
            }
            catch (Exception ex)
            {
                this.ErrorLabel.Text += ex.Message.ToString();
                this.ErrorLabel.RenderControl(writer);
            }
        }

        /// <summary>
        /// This is a Virtual Method who's implementation is 
        /// expection in Subclass. Mostly, modifying the values
        /// of desired column is expected in derived class
        /// </summary>
        protected virtual void ContentTypeSpecificAction()
        {
            throw new NotImplementedException(_message);
        }

        /// <summary>
        /// GridView's Sorting Event
        /// </summary>
        /// <param name="sender">GridView</param>
        /// <param name="e">GridViewSortEventArgs</param>
        protected void _gdAggregatorGrid_Sorting(object sender, GridViewSortEventArgs e)
        {
            string lastExpression = string.Empty;
            if (!string.IsNullOrEmpty(this.SortExpression))
                lastExpression = this.SortExpression;

            string lastDirection = _ascendingDirection;
            if (!string.IsNullOrEmpty(this.SortDirection))
                lastDirection = this.SortDirection;

            string newDirection = _ascendingDirection;
            if (e.SortExpression == lastExpression)
                newDirection = (lastDirection ==
                    _ascendingDirection) ? _descendingDirection : _ascendingDirection;

            this.SortExpression = e.SortExpression;
            this.SortDirection = newDirection;
            if (Enum.Equals(this.GroupBy, GroupByScope.None))
            {
                this._recentItemsDataView.Sort = string.Format(_sortTemplate,
                    e.SortExpression, newDirection);
                this._gdAggregatorGrid.DataSource = this._recentItemsDataView;
            }
            else
            {
                this._gdAggregatorGrid.DataSource = this.GetSortedItemsViewInGroups(e.SortExpression,
                    newDirection);
            }
        }

        /// <summary>
        /// GridView's sorting event handler
        /// </summary>
        /// <param name="sender">GridViewPageEventArgs</param>
        /// <param name="e">sender of the event : GridView</param>
        protected void _gdAggregatorGrid_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {
            this._gdAggregatorGrid.PageIndex = e.NewPageIndex;
            if (!string.IsNullOrEmpty(this.SortDirection) && !string.IsNullOrEmpty(this.SortExpression))
            {
                if (Enum.Equals(this.GroupBy, GroupByScope.None))
                {
                    // We have an active sorting, so this need to be preserved
                    this._recentItemsDataView.Sort = string.Format(_sortTemplate,
                        this.SortExpression, this.SortDirection);
                }
                else
                {
                    this._gdAggregatorGrid.DataSource = this.GetSortedItemsViewInGroups(this.SortExpression,
                        this.SortDirection);
                }
            }
        }

        /// <summary>
        /// Load Event of the Control
        /// </summary>
        /// <param name="e">Event Arguments</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
        }

        #endregion

        #region Private

        /// <summary>
        /// add the columns required in grid and
        /// also set the required properties lik, paging, soting, etc
        /// </summary>
        private void generateGrid()
        {
            this.ChromeType = PartChromeType.TitleAndBorder;
            this.SetPersonalizationDirty();
            this._lblErrorOutput = new Label();
            this._gdAggregatorGrid.AutoGenerateColumns = false;
            this._gdAggregatorGrid.ID = _gridViewId;
            this._gdAggregatorGrid.EmptyDataText = _emptyGridTemplateText;
            if (this.isWebpartOnStaticPage())
            {
                this.insertBoundFieldInGrid(this.ViewCreatedOnColumn,
                    GroupByScope.CreatedOn,
                    this.CreatedOnField,
                    _createdOnDisplayText,
                    this.CreatedOnField, false);
                this.insertBoundFieldInGrid(this.ViewModifiedOnColumn,
                    GroupByScope.ModifiedOn,
                    this.ModifiedOnField,
                    _modifiedOnDisplayText,
                    this.ModifiedOnField, false);
                this.insertBoundFieldInGrid(this.ViewListNameColumn,
                    GroupByScope.List,
                    this.ListNameField,
                    _listNameDisplayText,
                    this.ListNameField, false);
                this.insertBoundFieldInGrid(this.ViewSiteNameColumn,
                    GroupByScope.Site,
                    this.SiteNameField,
                    _siteNameDisplayText,
                    this.SiteNameField, true);
                if (this.ViewModifiedByColumn && !Enum.Equals(this.GroupBy, GroupByScope.ModifiedBy))
                {
                    HyperLinkField _userName = new HyperLinkField();
                    string[] _userFields = new string[1];
                    _userFields[0] = this.UserDisplayFormUrlField;
                    _userName.DataNavigateUrlFields = _userFields;
                    _userName.DataTextField = this.ModifiedByField;
                    _userName.HeaderText = _modifiedByDisplayText;
                    _userName.SortExpression = this.ModifiedByField;
                    _gdAggregatorGrid.Columns.Add(_userName);
                }

                _gdAggregatorGrid.AllowSorting = true;
                _gdAggregatorGrid.Sorting += new GridViewSortEventHandler(_gdAggregatorGrid_Sorting);

                if (!Enum.Equals(GroupBy, GroupByScope.None))
                {
                    _gdAggregatorGrid.AllowGrouping = true;
                    _gdAggregatorGrid.AllowGroupCollapse = true;
                    _gdAggregatorGrid.GroupField = this.getGroupByProperty(GroupBy);
                    _gdAggregatorGrid.GroupFieldDisplayName = this.GroupBy.ToString();
                    _gdAggregatorGrid.GridLines = GridLines.Both;
                }
                else
                {
                    _gdAggregatorGrid.AllowGrouping = false;
                    _gdAggregatorGrid.AllowGroupCollapse = false;
                }
            }

            ImageField _iconField = new ImageField();
            _iconField.DataImageUrlField = this.IconUrlField;
            _iconField.HeaderText = _typeDisplayText;
            _iconField.SortExpression = this.IconUrlField;
            this.uxAggregatorGridView.Columns.Insert(0, _iconField);

            if (this.PageSize != 0)
            {
                _gdAggregatorGrid.AllowPaging = true;
                _gdAggregatorGrid.PageSize = Convert.ToInt32(this.PageSize);
                _gdAggregatorGrid.PageIndexChanging +=
                    new GridViewPageEventHandler(_gdAggregatorGrid_PageIndexChanging);
            }
        }

        /// <summary>
        /// Get the appropriate column Name of the
        /// RecentItemsView depending on Current GroupByScope
        /// </summary>
        /// <param name="groupByEnum">Current GroupByScope</param>
        /// <returns>Name of column in string</returns>
        private string getGroupByProperty(GroupByScope groupByEnum)
        {
            switch (groupByEnum)
            {
                case GroupByScope.CreatedOn:
                    return this.CreatedOnField;
                case GroupByScope.ModifiedOn:
                    return this.ModifiedOnField;
                case GroupByScope.Site:
                    return this.SiteNameField;
                case GroupByScope.ModifiedBy:
                    return this.ModifiedByField;
                case GroupByScope.List:
                    return this.ListNameField;
                case GroupByScope.None:
                    return string.Empty;

            }
            return null;
        }

        /// <summary>
        /// This Method Adds Column to Data Table
        /// </summary>
        /// <param name="columnName">It takes the Column Name as parameter</param>
        private void AddColumnToDataTable(string columnName)
        {
            DataColumn _dataColumn = new DataColumn();
            _dataColumn.ColumnName = columnName;
            this._recentItemsDataTable.Columns.Add(_dataColumn);
        }

        /// <summary>
        /// generate the query string to be used 
        /// by the main webpart on the static page
        /// </summary>
        private void makeQueryString()
        {
            StringBuilder _queryStringBuilder = new StringBuilder();
            _queryStringBuilder.Append(string.Format(_queryStringTemplate.Substring
                (_queryStringTemplate.IndexOf(_amp) + 1), Constants.ItemLimitProperty, this.ItemLimit));
            _queryStringBuilder.Append(string.Format(_queryStringTemplate,
                Constants.PageSizeProperty, this.PageSize));
            _queryStringBuilder.Append(string.Format(_queryStringTemplate,
                Constants.ViewCreatedOnProperty, this.ViewCreatedOnColumn));
            _queryStringBuilder.Append(string.Format(_queryStringTemplate,
                Constants.ViewModifiedOnProperty, this.ViewModifiedOnColumn));
            _queryStringBuilder.Append(string.Format(_queryStringTemplate,
                Constants.ViewListNameProperty, this.ViewListNameColumn));
            _queryStringBuilder.Append(string.Format(_queryStringTemplate,
                Constants.ViewSiteNameProperty, this.ViewSiteNameColumn));
            _queryStringBuilder.Append(string.Format(_queryStringTemplate,
                Constants.ViewModifiedByProperty, this.ViewModifiedByColumn));
            _queryStringBuilder.Append(string.Format(_queryStringTemplate,
                Constants.SearchScopeProperty, this.SearchOptions));
            _queryStringBuilder.Append(string.Format(_queryStringTemplate,
                Constants.GroupByProperty, this.GroupBy));
            this._queryStrings = _queryStringBuilder.ToString();
        }

        /// <summary>
        /// Inserts a Bound Field in Grid
        /// </summary>
        /// <param name="fieldRequired">is this field requried in the grid's view</param>
        /// <param name="groupByScope">current fields group by scope</param>
        /// <param name="dataField">thee data text field to point to</param>
        /// <param name="headerText"> the header text of this field</param>
        /// <param name="sortExpression">the sort expression of this field</param>
        /// <param name="isSiteColumn">is this a site column</param>
        private void insertBoundFieldInGrid(bool fieldRequired,
            GroupByScope groupByScope,
            string dataField,
            string headerText,
            string sortExpression,
            bool isSiteColumn)
        {
            if (fieldRequired && !Enum.Equals(this.GroupBy, groupByScope))
            {
                SPBoundField _boundField = new SPBoundField();
                _boundField.DataField = dataField;
                _boundField.HeaderText = headerText;
                _boundField.SortExpression = sortExpression;
                if (isSiteColumn)
                {
                    switch (this.SearchOptions)
                    {
                        case SearchScope.Site: _gdAggregatorGrid.Columns.Add(_boundField);
                            break;
                        case SearchScope.Web: _gdAggregatorGrid.Columns.Add(_boundField);
                            break;
                        case SearchScope.None:
                            break;
                    }
                }
                else
                {
                    _gdAggregatorGrid.Columns.Add(_boundField);
                }

            }
        }

        /// <summary>
        /// Checks whether the 
        /// particular webpart instance is on
        /// the webpart page or static page
        /// </summary>
        /// <returns></returns>
        private bool isWebpartOnStaticPage()
        {
            return this.Page.Request.Url.AbsolutePath.ToLower().
                Contains(_staticPageRelativeUrl.ToLower());
        }

        #endregion

        #region Internal
        #endregion

        #endregion
    }
}
